-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OperationalError from SQlite that indicates a permissions problem. #2508
Conversation
@Mary011196, thanks for your PR! By analyzing the history of the files in this pull request, we identified @sampsyo, @geigerzaehler and @brunal to be potential reviewers. |
beets/ui/__init__.py
Outdated
util.displayable_path(dbpath) | ||
)) | ||
)%message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This handler already catches errors when we open the database. The bug report on this thread arises after the database is already opened, when it is accessed. So I think the new exception handling bit will need to go in the main function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
I add this in main but it gives me the message from the first UserError
excpetion that raised before.
except sqlite3.OperationalError as e:
if e.args[0] == "unable to open database file":
raise UserError(u"unable to open database file. It might be a permissions problem")
Is there a way to do it like db_query.InvalidQueryError
in order to check the mutate
function in db.py?
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, cool! Looks like you're almost there. There are actually two ways to go with this:
- Inside mutate, raise a
UserError
and let the top-level (main
) exception handling print the message. - Inside
main
, just catch theOperationalError
directly and print the error message there. (But don't raise a newUserError
.)
It's actually a difficult call to say what's better, but I like your idea of raising a new, specialized exception in mutate
. In fact, maybe we can invent a new error exception class, sort of like InvalidQueryError
, for filesystem access problems like this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
I' ve tried both ways but i have the same problem. In the first way i just add in mutate raise UserError("unable to open database file. It might be a permissions problem")
and in the second way i wrote in main
this:
except sqlite3.OperationalError as e:
if e.args[0] == "unable to open database file":
print("unable to open database file. It might be a permissions problem")
I wrote also a new error exception class
class AccessFileError(Exception):
"""Permission Exception. Exception that Specifically inidcates the
possibility of a permissions problem on database file.
"""
In order to work with this way i have to raise an AccessFileError
in mutate and catch it in the main
?
Thank you very much!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i fixed it and i tried it with all ways. But it works when i deny the write permission in my database file and the traceback that gives me is attempt to write a readonly database
. Is this right??
Thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to work with this way i have to raise an AccessFileError in mutate and catch it in the main?
Yes, exactly!
But it works when i deny the write permission in my database file and the traceback that gives me is attempt to write a readonly database. Is this right??
It's somewhat hard to know exactly what causes specific kinds of errors in the SQLite library, which hides the precise details of what went wrong. But if you see that error when setting the database file to have permissions that prevent writing by your user, that does sound like something we should handle—perhaps in addition to the existing "unable to open database file" error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But when it gives me the "unable to open datapase file" error it prints the message of UserError that raise the _open_library. Maybe the way i change my settings is wrong?
Thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm… can you try pushing your updated code so it appears here in the PR? Then I can take a look at how it's actually working.
beets/dbcore/db.py
Outdated
cursor = self.db._connection().execute(statement, subvals) | ||
raise AccessFileError("unable to open database file. It might be a permissions problem") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be in an exception handler for OperationalError.
beets/dbcore/db.py
Outdated
|
||
def script(self, statements): | ||
"""Execute a string containing multiple SQL statements.""" | ||
self.db._connection().executescript(statements) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it seems small, but we need this blank line here for consistency.
beets/dbcore/db.py
Outdated
@@ -32,6 +32,10 @@ | |||
from .query import MatchQuery, NullSort, TrueQuery | |||
import six | |||
|
|||
class AccessFileError(Exception): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "DBAccessError" for clarity?
beets/dbcore/db.py
Outdated
@@ -32,6 +32,10 @@ | |||
from .query import MatchQuery, NullSort, TrueQuery | |||
import six | |||
|
|||
class AccessFileError(Exception): | |||
"""UI exception. Commands should throw this in order to display | |||
nonrecoverable errors to the user. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the description for UserError? Here's an alternative docstring:
The SQLite database became inaccessible. This can happen when trying to read or write the database when, for example, the database file is deleted or otherwise disappears. There is probably no way to recover from this error.
beets/dbcore/db.py
Outdated
cursor = self.db._connection().execute(statement, subvals) | ||
return cursor.lastrowid | ||
except sqlite3.OperationalError as e: | ||
raise AccessFileError("unable to open database file. It might be a permissions problem") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is where the check for error strings like "attempt to write a readonly database" should occur. (For what it's worth, I did a little experiment—that's the message that appears if I try to access the database after deleting the file from my disk!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, i have to add an if that check if e.args[0] is equals with "attempt to write a readonly database file" and another that checks if e.args[0] is equals with "unable to open database file"? I already tried it and when the message is "unable to open database file" it gives me again the message of UserError.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! Or we can just have one if
that checks whether it's either of those things:
if e.args[0] in ('string1', 'string2'):
I don't quite understand what you mean about the UserError… is some other code producing a UserError exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
I think i fixed it. Is it right?
Thank you!!
And re-use the SQLite error string instead of a hand-written one for now.
This looks great! Thank you for your contribution! I just pushed a few small changes here; let's see what Travis says. |
Thank you too. I will continue with the next issue. Will my code be merged? Thank you again! |
Looks like everything's in order. Merging now! ✨ |
Fixes 1676.